package com.dragon.backstage.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.TokenSign;
import cn.dev33.satoken.stp.StpUtil;
import com.dragon.backstage.domain.param.userOnline.UserOnlineKickOutParam;
import com.dragon.backstage.domain.param.userOnline.UserOnlineLogoutParam;
import com.dragon.backstage.domain.vo.userOnline.UserOnlineVo;
import com.dragon.backstage.service.UserOnlineService;
import com.dragon.common.utils.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * 在线用户服务实现类
 *
 * @author dragon
 * @version 1.0
 * @date 2024/10/19 20:05
 */
@Slf4j
@Service
public class UserOnlineServiceImpl implements UserOnlineService {

    /**
     * 在线用户列表
     *
     * @return 在线用户列表
     */
    @Override
    public AjaxResult<List<UserOnlineVo>> userOnlineList() {
        // 查询所有账号 Session 会话
        List<String> sessionIds = StpUtil.searchSessionId("", 0, -1, false);

        List<TokenSign> tokenSigns = new ArrayList<>(16);
        for (String sessionId : sessionIds) {
            SaSession saSession = StpUtil.getSessionBySessionId(sessionId);
            // 获取账号下所有登录的设备
            if (CollectionUtils.isNotEmpty(saSession.getTokenSignList())) {
                tokenSigns.addAll(saSession.getTokenSignList());
            }
        }

        List<UserOnlineVo> userOnlineVos = new ArrayList<>();
        for (TokenSign tokenSign : tokenSigns) {
            SaSession saSession = StpUtil.getTokenSessionByToken(tokenSign.getValue());

            String tokenId = saSession.getString(UserOnlineVo.TOKEN_ID);
            String account = saSession.getString(UserOnlineVo.ACCOUNT);
            String ipAddr = saSession.getString(UserOnlineVo.IP_ADDR);
            String loginLocation = saSession.getString(UserOnlineVo.LOGIN_LOCATION);
            String loginDevice = saSession.getString(UserOnlineVo.LOGIN_DEVICE);
            String browser = saSession.getString(UserOnlineVo.BROWSER);
            String os = saSession.getString(UserOnlineVo.OS);
            LocalDateTime loginTime = saSession.getModel(UserOnlineVo.LOGIN_TIME, LocalDateTime.class);


            UserOnlineVo userOnlineVo = UserOnlineVo
                .builder()
                // tokenId 建议使用加密传输，这里只是示例
                .tokenId(StringUtils.isNotBlank(tokenId) ? tokenId : tokenSign.getValue())
                .account(account)
                .ipAddr(ipAddr)
                .loginLocation(loginLocation)
                .loginDevice(StringUtils.isNotBlank(loginDevice) ? loginDevice : tokenSign.getDevice())
                .browser(browser)
                .os(os)
                .loginTime(loginTime)
                .build();

            userOnlineVos.add(userOnlineVo);
        }

        if (CollectionUtils.isNotEmpty(userOnlineVos)) {
            userOnlineVos.sort(Comparator.comparing(UserOnlineVo::getLoginTime).reversed());
        }

        return AjaxResult.succeedWith(userOnlineVos);
    }

    /**
     * 注销在线用户
     *
     * @param userOnlineLogoutParam 注销参数
     * @return 注销结果
     */
    @Override
    public AjaxResult<Void> userOnlinelogOut(UserOnlineLogoutParam userOnlineLogoutParam) {
        AjaxResult<Void> check = UserOnlineLogoutParam.check(userOnlineLogoutParam);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        if (userOnlineLogoutParam.getLogoutType() == 1) {
            StpUtil.logoutByTokenValue(userOnlineLogoutParam.getTokenId());
        }

        if (userOnlineLogoutParam.getLogoutType() == 2) {
            Object userId = StpUtil.getLoginIdByToken(userOnlineLogoutParam.getTokenId());
            if (Objects.isNull(userId)) {
                return AjaxResult.failed("tokenId已注销");
            }

            StpUtil.logout(userId);
        }

        return AjaxResult.succeed();
    }

    /**
     * 踢掉在线用户
     *
     * @param userOnlineKickOutParam 踢人下线请求参数
     * @return 踢人下线结果
     */
    @Override
    public AjaxResult<Void> userOnlineKickOut(UserOnlineKickOutParam userOnlineKickOutParam) {
        AjaxResult<Void> check = UserOnlineKickOutParam.check(userOnlineKickOutParam);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        if (userOnlineKickOutParam.getKickOutType() == 1) {
            StpUtil.kickoutByTokenValue(userOnlineKickOutParam.getTokenId());
        }

        if (userOnlineKickOutParam.getKickOutType() == 2) {
            Object userId = StpUtil.getLoginIdByToken(userOnlineKickOutParam.getTokenId());
            if (Objects.isNull(userId)) {
                return AjaxResult.failed("tokenId已注销");
            }

            StpUtil.kickout(userId);
        }

        return AjaxResult.succeed();
    }

}
